import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from ttkbootstrap.dialogs import Messagebox, Dialog
import tkinter as tk
from tkinter import filedialog
import random
import csv
import datetime
import os

class DataManager:
    """数据管理类，负责数据的存储和操作"""
    def __init__(self):
        self.data = []
        # 初始化一些示例数据
        self.init_sample_data()
        
    def init_sample_data(self):
        """初始化示例数据"""
        categories = ["电子产品", "服装", "食品", "图书", "家居"]
        statuses = ["在售", "缺货", "促销", "停产"]
        
        for i in range(1, 21):
            item = {
                "id": i,
                "name": f"商品{i}",
                "category": random.choice(categories),
                "price": round(random.uniform(10, 1000), 2),
                "stock": random.randint(0, 100),
                "status": random.choice(statuses)
            }
            self.data.append(item)
            
    def get_all_data(self):
        """获取所有数据"""
        return self.data
    
    def get_data_by_id(self, item_id):
        """通过ID获取数据"""
        for item in self.data:
            if item["id"] == item_id:
                return item
        return None
    
    def add_data(self, new_item):
        """添加新数据"""
        # 生成新ID
        new_id = max(item["id"] for item in self.data) + 1 if self.data else 1
        new_item["id"] = new_id
        self.data.append(new_item)
        return new_id
    
    def update_data(self, updated_item):
        """更新数据"""
        for i, item in enumerate(self.data):
            if item["id"] == updated_item["id"]:
                self.data[i] = updated_item
                return True
        return False
    
    def delete_data(self, item_id):
        """删除数据"""
        for i, item in enumerate(self.data):
            if item["id"] == item_id:
                del self.data[i]
                return True
        return False
    
    def search_data(self, keyword):
        """搜索数据"""
        if not keyword:
            return self.data
            
        keyword = keyword.lower()
        results = []
        for item in self.data:
            # 检查关键字是否匹配任何字段
            if (keyword in str(item["id"]).lower() or 
                keyword in item["name"].lower() or 
                keyword in item["category"].lower() or 
                keyword in str(item["price"]).lower() or 
                keyword in str(item["stock"]).lower() or 
                keyword in item["status"].lower()):
                results.append(item)
        return results
        
    def export_to_csv(self, file_path, data=None):
        """导出数据到CSV文件"""
        if data is None:
            data = self.data
            
        if not data:
            return False, "没有数据可导出"
            
        try:
            # 确保目录存在
            directory = os.path.dirname(file_path)
            if directory and not os.path.exists(directory):
                os.makedirs(directory)
                
            # 写入CSV文件
            with open(file_path, 'w', newline='', encoding='utf-8-sig') as csvfile:
                fieldnames = ['id', 'name', 'category', 'price', 'stock', 'status']
                writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
                
                # 写入表头
                writer.writeheader()
                
                # 写入数据
                for item in data:
                    writer.writerow(item)
                    
            return True, f"数据已成功导出到 {file_path}"
        except Exception as e:
            return False, f"导出失败: {str(e)}"

class ItemFormDialog:
    """用于添加和编辑项目的对话框，使用ttkbootstrap的Toplevel组件"""
    def __init__(self, parent, title, item=None, on_success=None):
        self.parent = parent
        self.item = item if item else {}
        self.on_success = on_success  # 成功回调函数
        
        # 创建Toplevel窗口
        self.window = ttk.Toplevel(parent)
        self.window.title(title)
        self.window.geometry("400x300")
        self.window.resizable(False, False)
        self.window.transient(parent)  # 设置为主窗口的子窗口
        self.window.grab_set()  # 模态窗口
        
        # 创建对话框内容
        self.create_widgets()
        
    def create_widgets(self):
        """创建对话框内容"""
        main_frame = ttk.Frame(self.window, padding=10)
        main_frame.pack(fill=BOTH, expand=YES)
        
        # 内容区域
        content_frame = ttk.Frame(main_frame)
        content_frame.pack(fill=BOTH, expand=YES, pady=(0, 10))
        
        # 名称
        ttk.Label(content_frame, text="商品名称:").grid(row=0, column=0, sticky=W, pady=5)
        self.name_var = ttk.StringVar(value=self.item.get("name", ""))
        ttk.Entry(content_frame, textvariable=self.name_var).grid(row=0, column=1, sticky=EW, pady=5)
        
        # 类别
        ttk.Label(content_frame, text="类别:").grid(row=1, column=0, sticky=W, pady=5)
        categories = ["电子产品", "服装", "食品", "图书", "家居"]
        self.category_var = ttk.StringVar(value=self.item.get("category", categories[0]))
        ttk.Combobox(content_frame, textvariable=self.category_var, values=categories).grid(
            row=1, column=1, sticky=EW, pady=5)
        
        # 价格
        ttk.Label(content_frame, text="价格:").grid(row=2, column=0, sticky=W, pady=5)
        self.price_var = ttk.StringVar(value=str(self.item.get("price", "0.00")))
        ttk.Entry(content_frame, textvariable=self.price_var).grid(row=2, column=1, sticky=EW, pady=5)
        
        # 库存
        ttk.Label(content_frame, text="库存:").grid(row=3, column=0, sticky=W, pady=5)
        self.stock_var = ttk.StringVar(value=str(self.item.get("stock", "0")))
        ttk.Entry(content_frame, textvariable=self.stock_var).grid(row=3, column=1, sticky=EW, pady=5)
        
        # 状态
        ttk.Label(content_frame, text="状态:").grid(row=4, column=0, sticky=W, pady=5)
        statuses = ["在售", "缺货", "促销", "停产"]
        self.status_var = ttk.StringVar(value=self.item.get("status", statuses[0]))
        ttk.Combobox(content_frame, textvariable=self.status_var, values=statuses).grid(
            row=4, column=1, sticky=EW, pady=5)
        
        content_frame.grid_columnconfigure(1, weight=1)
        
        # 按钮区域
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill=X, side=BOTTOM)
        
        ttk.Button(button_frame, text="确定", command=self.on_ok).pack(side=RIGHT, padx=5)
        ttk.Button(button_frame, text="取消", command=self.on_cancel).pack(side=RIGHT, padx=5)
        
    def on_ok(self):
        """确定按钮回调"""
        try:
            # 验证输入
            if not self.name_var.get().strip():
                Messagebox.show_error("商品名称不能为空", "输入错误")
                return
                
            try:
                price = float(self.price_var.get())
                if price < 0:
                    raise ValueError("价格不能为负数")
            except ValueError as e:
                Messagebox.show_error(f"价格输入无效: {str(e)}", "输入错误")
                return
                
            try:
                stock = int(self.stock_var.get())
                if stock < 0:
                    raise ValueError("库存不能为负数")
            except ValueError as e:
                Messagebox.show_error(f"库存输入无效: {str(e)}", "输入错误")
                return
                
            # 准备结果数据
            result_data = {
                "name": self.name_var.get().strip(),
                "category": self.category_var.get(),
                "price": price,
                "stock": stock,
                "status": self.status_var.get()
            }
            
            # 如果是编辑模式，保留ID
            if "id" in self.item:
                result_data["id"] = self.item["id"]
                
            # 调用成功回调函数
            if self.on_success:
                self.on_success(result_data)
                
            # 关闭窗口
            self.window.destroy()
        except Exception as e:
            Messagebox.show_error(f"发生错误: {str(e)}", "错误")
            
    def on_cancel(self):
        """取消按钮回调"""
        self.window.destroy()

class TreeviewCRUDApp:
    """主应用类"""
    def __init__(self, root):
        self.root = root
        self.root.title("Treeview 表格 CRUD 示例")
        self.root.geometry("1000x600")
        
        # 初始化数据管理器
        self.data_manager = DataManager()
        
        # 创建界面
        self.create_widgets()
        
        # 加载数据
        self.load_data()
    
    def create_widgets(self):
        """创建界面组件"""
        # 顶部搜索和操作区
        top_frame = ttk.Frame(self.root, padding=10)
        top_frame.pack(fill=X)
        
        # 搜索框
        ttk.Label(top_frame, text="搜索:").pack(side=LEFT, padx=5)
        self.search_var = ttk.StringVar()
        search_entry = ttk.Entry(top_frame, textvariable=self.search_var, width=30)
        search_entry.pack(side=LEFT, padx=5)
        search_entry.bind("<Return>", lambda e: self.search_data())
        
        ttk.Button(top_frame, text="搜索", command=self.search_data).pack(side=LEFT, padx=5)
        ttk.Button(top_frame, text="清除搜索", command=self.clear_search).pack(side=LEFT, padx=5)
        
        # 操作按钮
        button_frame = ttk.Frame(top_frame)
        button_frame.pack(side=RIGHT)
        
        ttk.Button(button_frame, text="添加", command=self.add_item).pack(side=LEFT, padx=5)
        ttk.Button(button_frame, text="编辑", command=self.edit_item).pack(side=LEFT, padx=5)
        ttk.Button(button_frame, text="删除", command=self.delete_item).pack(side=LEFT, padx=5)
        ttk.Button(button_frame, text="刷新", command=self.refresh_data).pack(side=LEFT, padx=5)
        ttk.Button(button_frame, text="导出", command=self.export_data).pack(side=LEFT, padx=5)
        
        # 表格区域
        table_frame = ttk.Frame(self.root, padding=10)
        table_frame.pack(fill=BOTH, expand=YES)
        
        # 创建列定义并保存到类变量
        self.columns = [
            {"name": "id", "text": "ID", "width": 50, "anchor": CENTER},
            {"name": "name", "text": "商品名称", "width": 200},
            {"name": "category", "text": "类别", "width": 100},
            {"name": "price", "text": "价格", "width": 100, "anchor": E},
            {"name": "stock", "text": "库存", "width": 80, "anchor": CENTER},
            {"name": "status", "text": "状态", "width": 80, "anchor": CENTER}
        ]
        columns = self.columns
        
        self.tree = ttk.Treeview(
            table_frame,
            columns=[col["name"] for col in columns],
            show="headings"
        )
        
        # 设置列并添加排序功能
        for col in columns:
            self.tree.heading(col["name"], text=col["text"], 
                             command=lambda c=col["name"]: self.sort_column(c, False))
            self.tree.column(
                col["name"], 
                width=col["width"],
                anchor=col.get("anchor", W)
            )
        
        # 用于排序的变量
        self.sort_column_name = None
        self.sort_reverse = False
        
        # 添加滚动条
        scrollbar_y = ttk.Scrollbar(table_frame, orient=VERTICAL, command=self.tree.yview)
        scrollbar_x = ttk.Scrollbar(table_frame, orient=HORIZONTAL, command=self.tree.xview)
        self.tree.configure(yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set)
        
        # 布局
        self.tree.grid(row=0, column=0, sticky=NSEW)
        scrollbar_y.grid(row=0, column=1, sticky=NS)
        scrollbar_x.grid(row=1, column=0, sticky=EW)
        table_frame.grid_rowconfigure(0, weight=1)
        table_frame.grid_columnconfigure(0, weight=1)
        
        # 绑定双击事件用于编辑
        self.tree.bind("<Double-1>", lambda e: self.edit_item())
        
        # 状态栏
        self.status_var = ttk.StringVar(value="就绪")
        status_bar = ttk.Label(self.root, textvariable=self.status_var, relief=SUNKEN, anchor=W)
        status_bar.pack(side=BOTTOM, fill=X)
    
    def load_data(self, data=None):
        """加载数据到表格"""
        # 清空现有数据
        for item in self.tree.get_children():
            self.tree.delete(item)
            
        # 如果没有提供数据，则使用所有数据
        if data is None:
            data = self.data_manager.get_all_data()
            
        # 添加数据到表格
        for item in data:
            self.tree.insert("", END, values=(
                item["id"],
                item["name"],
                item["category"],
                f"¥{item['price']:.2f}",  # 格式化价格
                item["stock"],
                item["status"]
            ))
            
        # 更新状态栏
        self.status_var.set(f"显示 {len(data)} 条记录，共 {len(self.data_manager.get_all_data())} 条记录")
    
    def add_item(self):
        """添加新项"""
        # 定义添加成功的回调函数
        def on_add_success(new_item):
            new_id = self.data_manager.add_data(new_item)
            self.refresh_data()
            Messagebox.show_info(f"成功添加商品，ID: {new_id}", "成功")
        
        # 显示添加对话框，并传入回调函数
        ItemFormDialog(self.root, "添加商品", on_success=on_add_success)

    def edit_item(self):
        """编辑选中项"""
        selected = self.tree.selection()
        if not selected:
            Messagebox.show_warning("请先选择要编辑的项目", "提示")
            return
            
        # 获取选中项的数据
        item_id = int(self.tree.item(selected[0], "values")[0])
        item = self.data_manager.get_data_by_id(item_id)
        
        if item:
            # 定义编辑成功的回调函数
            def on_edit_success(updated_item):
                if self.data_manager.update_data(updated_item):
                    self.refresh_data()
                    Messagebox.show_info("商品信息已更新", "成功")
            
            # 显示编辑对话框，并传入回调函数和当前数据
            ItemFormDialog(self.root, "编辑商品", item=item, on_success=on_edit_success)
    
    def delete_item(self):
        """删除选中项"""
        selected = self.tree.selection()
        if not selected:
            Messagebox.show_warning("请先选择要删除的项目", "提示")
            return
            
        # 获取选中项ID
        item_id = int(self.tree.item(selected[0], "values")[0])
        item_name = self.tree.item(selected[0], "values")[1]
        
        # 确认删除
        if Messagebox.yesno(f"确定要删除商品 '{item_name}' 吗？", "确认删除") == "Yes":
            if self.data_manager.delete_data(item_id):
                self.tree.delete(selected)
                self.refresh_data()
                Messagebox.show_info("商品已删除", "成功")
    
    def search_data(self):
        """搜索数据"""
        keyword = self.search_var.get()
        results = self.data_manager.search_data(keyword)
        self.load_data(results)
        self.status_var.set(f"搜索 '{keyword}'，找到 {len(results)} 条记录")
    
    def clear_search(self):
        """清除搜索条件"""
        self.search_var.set("")
        self.refresh_data()
    
    def refresh_data(self):
        """刷新数据"""
        self.load_data()
    
    def sort_column(self, col, reverse):
        """对列进行排序"""
        # 保存当前排序状态
        self.sort_column_name = col
        self.sort_reverse = reverse
        
        # 获取当前显示的数据
        data = self.data_manager.search_data(self.search_var.get())
        
        # 定义排序键
        def sort_key(item):
            value = item[col]
            # 尝试将数值型数据转换为对应的类型进行排序
            if col == 'price':
                return float(value)
            elif col == 'stock' or col == 'id':
                return int(value)
            return str(value).lower()
        
        # 对数据进行排序
        data.sort(key=sort_key, reverse=reverse)
        
        # 重新加载排序后的数据
        self.load_data(data)
        
        # 更新标题以显示排序方向
        for c in [col["name"] for col in self.columns]:
            if c == col:
                # 添加排序指示器
                heading_text = f"{self.get_column_text(c)} {'↑' if reverse else '↓'}"
                # 重新设置标题和排序命令（切换排序方向）
                self.tree.heading(c, text=heading_text, 
                                 command=lambda c=c: self.sort_column(c, not reverse))
            else:
                # 恢复原始标题
                self.tree.heading(c, text=self.get_column_text(c),
                                 command=lambda c=c: self.sort_column(c, False))
    
    def get_column_text(self, col_name):
        """根据列名获取原始列文本"""
        for col in self.columns:
            if col["name"] == col_name:
                return col["text"]
        return col_name
        
    def export_data(self):
        """导出数据功能"""
        # 询问导出选项
        export_option = Messagebox.yesnocancel(
            "请选择导出选项:\n- 是: 仅导出选中项\n- 否: 导出当前显示的所有项\n- 取消: 取消导出", 
            "导出数据"
        )
        
        if export_option == 'Cancel':
            return
            
        # 确定要导出的数据
        if export_option == 'Yes':
            # 导出选中项
            selected = self.tree.selection()
            if not selected:
                Messagebox.show_warning("没有选中任何项目", "提示")
                return
                
            data_to_export = []
            for item_id in selected:
                item_id_value = int(self.tree.item(item_id, "values")[0])
                item = self.data_manager.get_data_by_id(item_id_value)
                if item:
                    data_to_export.append(item)
        else:
            # 导出当前显示的所有项
            data_to_export = self.data_manager.search_data(self.search_var.get())
            
        if not data_to_export:
            Messagebox.show_warning("没有数据可导出", "提示")
            return
            
        # 生成默认文件名
        default_filename = f"商品数据_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
        
        # 打开文件保存对话框让用户选择保存位置
        file_path = filedialog.asksaveasfilename(
            parent=self.root,
            title="保存CSV文件",
            initialdir=os.getcwd(),
            initialfile=default_filename,
            defaultextension=".csv",
            filetypes=[("CSV文件", "*.csv"), ("所有文件", "*.*")]
        )
        
        # 如果用户取消选择，则返回
        if not file_path:
            return
            
        # 确保文件扩展名为.csv
        if not file_path.endswith('.csv'):
            file_path += '.csv'
        
        # 执行导出
        success, message = self.data_manager.export_to_csv(file_path, data_to_export)
        
        if success:
            Messagebox.show_info(message, "导出成功")
        else:
            Messagebox.show_error(message, "导出失败")

if __name__ == "__main__":
    app = ttk.Window(themename="flatly")
    treeview_app = TreeviewCRUDApp(app)
    app.mainloop()
    